/** @file    WoshModule.cpp
 *  @author  Alessandro Polo
 *  @version $Id: WoshModule.cpp 2829 2010-08-02 20:45:47Z alex $
 *  @brief
 * File containing methods for the wosh::WoshModule class.
 * The header for this class can be found in WoshModule.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/
 
 #include <core/WoshModule.h>
 #include <core/ObjectAllocator.h>
 #include <core/WoshKernel.h>
 #include <core/SecurityManager.h>
 #include <core/Settings.h>
 #include <core/MethodsCommon.h>
 #include <core/MessageFilter.h>
 #include <core/MessageProcessingCommon.h>
 #include <core/List.h>
 #include <core/DataModels.h>


using namespace std;
namespace wosh {

 WOSH_REGISTER_INTERFACE(wosh::WoshModule, "wosh::Object", 1.00, _static_WoshModule )

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS

WoshModule::WoshModule( const WoshKernel* parent, const std::string& name, const std::string& uri )
	: Object(parent) {

	Object::setName( name );
	Object::getURI().fromString( uri );
	Object::getURI().registerGlobal();

	Log.setContext( Object::getName() );
	Log.setIndent( 2 );
	Log.setLevel( LOG_INFO );

	this->initState = 0;

	Log(LOG_DEBUG, " Initializing Properties.." );
	Properties.set( _KEY_Version,			0.0, Permission( Permission::Read ) );
	Properties.set( _KEY_DebugLevel,		LogContext::getLogLevelAsString(LOG_INFO), Permission::RW_RW_R__() );
	Properties.set( _WoshModule_KEY_State,	0, Permission( Permission::Read ) );

	Log(LOG_DEBUG, " Registering Methods.." );
	Methods.setPermission( Object::getPermission(), Permission::Overwrite_All, true, true );
	Methods.getListPermission().setMask( Permission::Read, Permission::Read, Permission::Read );

	MethodPropertyT::createMethods( &Methods, &Properties, &Log );

	MethodChT::createMethods( &Methods, this, &Properties, &Log );

	MethodList* mmListMethods = Methods.create<MethodList>( _METHOD_ListMethods, "List Methods", Permission(Permission::RX) );
	mmListMethods->setDataFieldExtractor( DataFieldExtractor<Method>::createFor< DataAdapterMapT<std::string,Method> >(Methods, "Module Methods") );

	MethodList* mmListInterfaces = Methods.create<MethodList>( _METHOD_ListInterfaces, "List Interfaces", Permission(Permission::RX) );
	mmListInterfaces->setDataFieldExtractor( DataFieldExtractor<ObjectTypeInfo>::createFor< DataAdapterMapT<std::string,ObjectTypeInfo> >(Interfaces, "Module Interfaces") );
	MethodRetrieveObject<InterfacesProvider>* mmGetInterfaces = Methods.create< MethodRetrieveObject<InterfacesProvider> >( _METHOD_GetInterfacesProvider, "Get InterfacesProvider object", Permission(Permission::RX) );
	mmGetInterfaces->configure(&Interfaces, NULL, NULL);

 }

//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////// KERNEL EVENTS

WRESULT WoshModule::kernel_StateChanged( int new_state, int ) {
	switch(new_state) {
		case WoshKernel::STATE_INITIALIZING:	return onKernelInitializing();
		case WoshKernel::STATE_INITIALIZED:		return onKernelInitialized();
		case WoshKernel::STATE_RUNNING:			return onKernelRunning();
		case WoshKernel::STATE_STOPPING:		return onKernelStopping();
		case WoshKernel::STATE_STOPPED:			return onKernelStopped();
		case WoshKernel::STATE_FAILURE:			return WRET_OK;
		case WoshKernel::STATE_DESTROYING:		return WRET_OK;
		default:								return WRET_ERR_PARAM;
	 }
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT WoshModule::onKernelInitializing() {
	Log.setContext( Object::getName() );
	Interfaces.createFor(this);
	Properties.set( _KEY_type, getClassName(), Permission(Permission::Read) );
	Properties.set( _KEY_interfaces, Interfaces.toString(), Permission(Permission::Read) );
	Properties.updateObjectKeys(this);
	Properties.setPermission( Object::getPermission(), Permission::Overwrite_All, true, true );
	Properties.setPropertiesProviderListener(this);

	Log(LOG_VERBOSE, ":onKernelInitializing() Connecting 'wosh.Bus.Core'.." );
	BusCore.setMessageHandler(this);
	WRESULT bus_connected = BusCore.connect( _Bus_Core );
	if ( WFAILED(bus_connected) )
		Log(LOG_CRITICAL, ":onKernelInitializing() FAILED#%d Connecting Bus (wosh.Bus.Core)..", bus_connected );

	this->initState = 1;
	Properties.transactionBeginWrite();
	Properties.update( _WoshModule_KEY_State, this->initState );
	Properties.transactionEnd();

	PropertiesProvider* props = WoshKernel::getInstance()->settings().getSettingsOf( this->getName() );
	if ( props == NULL ) {
		Log(LOG_WARNING, ":onKernelInitializing() Missing Setting group '%s'", this->getName().c_str() );
		return WRET_OK;
	 }
	this->Properties.intersect( *props, true, false);
	// security bug Properties.setPermission( Object::getPermission(), Permission::Overwrite_All, true, true );
	Log(LOG_DEBUG, ":onKernelInitializing() (pre)Initialized." );
	return bus_connected;
 }

WRESULT WoshModule::onKernelInitialized() {
	Log(LOG_DEBUG, ":onKernelInitialized() (post)Initialized." );
	return WRET_OK;
 }
WRESULT WoshModule::onKernelRunning() {
	Log(LOG_DEBUG, ":onKernelRunning() Running." );
	return WRET_OK;
 }

WRESULT WoshModule::onKernelStopping() {
	this->initState = 2;
	Properties.transactionBeginWrite();
	Properties.update( _WoshModule_KEY_State, this->initState );
	Properties.transactionEnd();
	WRESULT bus_disconnected = BusCore.disconnect();
	if ( WFAILED(bus_disconnected) )
		Log(LOG_WARNING, ":onKernelStopping() FAILED#%d DisConnecting Bus (wosh.Bus.Core)..", bus_disconnected );
	Log(LOG_DEBUG, ":onKernelStopping() (pre)DeInitialized." );
	return bus_disconnected;
 }

WRESULT WoshModule::onKernelStopped() {
	Log(LOG_DEBUG, ":onKernelInitializing() (post)DeInitialized." );
	return WRET_OK;
 }

/////////////////////////////////////////////////////////////////////////////////////////////// KERNEL EVENTS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////// PROPERTY EVENTS

bool WoshModule::updatingProperty( bool& , const Variant& value_proposed, Property& property_current, const PropertiesProvider* ) {
	if ( property_current.getKey() == _KEY_DebugLevel )
		return MPC_PropertyParse_LogLevel( value_proposed, this->Log );
	// not handled, sound strange but probably its ok since we are the lower (base) implementation
	return true;
 }

///////////////////////////////////////////////////////////////////////////////////////////// PROPERTY EVENTS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT WoshModule::diagnostic() {
	WRESULT ret = WRET_OK;
	Log(LOG_VERBOSE, ":diagnostic() : Starting BundleGeneric-Diagnostic" );
	// get Name
	if ( Object::getName() == "" ) {
		Log(LOG_CRITICAL, " Diagnostic : FATAL Empty Object::Name!" );
		ret += WRET_ERR_INTERNAL;
	 }
	else if ( Object::getName() == "wosh.BundleGeneric" )
		Log(LOG_WARNING, " Diagnostic : FATAL Default Object::Name! [wosh.BundleGeneric]" );
	// check BusCore..
	bool bus_connected = BusCore.isConnected();
	if ( bus_connected )
		Log(LOG_VERBOSE, " Diagnostic : BusCore[wosh.Bus.Core] is Connected." );
	else {
		Log(LOG_CRITICAL, " Diagnostic : FATAL BusCore[wosh.Bus.Core] is DISConnected!" );
		ret += WRET_ERR_INTERNAL;
	 }
	Log(LOG_INFO, ":diagnostic() : Finished BundleGeneric-Diagnostic [%d]", ret );
	return ret;
 }

////////////////////////////////////////////////////////////////////////////////////////// (DE)INITIALIZATION
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////// BUS EVENTS

void WoshModule::busMessage( const Message& message, const Bus* source ) {
	if ( message.isEmpty() || !message.getContent()->isRequest() ) return;
	if ( !MessageFilter::isMessageTarget(message, this->getURI(), &this->Properties) )
		return;
	Message* reply = MPC_busMessageRequest( message, this->Methods, this->Log );
	if ( reply == NULL ) return;
	signMessage(reply);
	if ( source != NULL )
		source->postMessage(reply);
	else
		BusCore.postMessage(reply);
 }

////////////////////////////////////////////////////////////////////////////////////////////////// BUS EVENTS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

SecurityToken* WoshModule::signMessage( Message* message ) const {
	if ( message == NULL ) return NULL;
	message->setSource(this);
	return SecurityManager::getCredentialImplicit().signMessage(message, this);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

DataFieldCollector<WoshModule>* WoshModule::getDataFields() {
	DataFieldCollector<WoshModule>* fields = new DataFieldCollector<WoshModule>();
	fields->add<const std::string&, Variant>(&WoshModule::getName, "Name", 0);
	fields->add<const char*, Variant>(&WoshModule::getClassName, "Type", 1);
	fields->add<const URI&,URI>(&WoshModule::getURI, "URI", 2);
	DataFieldSubWrapperT<WoshModule, const InterfacesProvider&, List*, void>* dfwInterfacesList;
	dfwInterfacesList = new DataFieldSubWrapperT<WoshModule, const InterfacesProvider&, List*, void>(&WoshModule::getInterfaces, &InterfacesProvider::toList, "Interfaces", 3);
	dfwInterfacesList->info.visible = false;
	fields->add(dfwInterfacesList);
	fields->add<const Permission&,Permission>(&WoshModule::getPermission, "Permission", 4, false);
	fields->add<const std::string&,Variant>(&WoshModule::getEntityID, "EntityID", 5, false);
	DataFieldSubWrapperT<WoshModule, const InterfacesProvider&, std::string, Variant>* dfwInterfacesStr;
	dfwInterfacesStr = new DataFieldSubWrapperT<WoshModule, const InterfacesProvider&, std::string, Variant>(&WoshModule::getInterfaces, &InterfacesProvider::toString, "Interfaces[Str]", 3);
	dfwInterfacesStr->info.visible = false;
	fields->add(dfwInterfacesStr);
	return fields;
 }


//////////////////////////////////////////////////////////////////////////////////////////////////////////////

}; // namespace wosh
